#pragma once
#include <windows.h>
#include <string>
#include "ProcessInformation.hpp"
#include <filesystem>

namespace CppWinApi::Windows::WinProcess
{
    /// @brief 等待一个进程退出
    /// @param pid 进程 id
    /// @param dwMilliseconds 等待时长
    /// @return 退出码
    static DWORD WaitProcessExit(DWORD pid, DWORD dwMilliseconds = INFINITE);

    /// @brief 启动一个进程
    /// @param exePath exe文件路径
    /// @param args 启动参数
    /// @param dwCreationFlags 启动标志
    /// @param workDirectory
    /// @return 返回进程信息
    static ProcessInformation StartProcess(
        const std::string& exePath,
        DWORD dwCreationFlags = 0,
        const std::string& args = "",
        const std::string& workDirectory = "");

    /// @brief 启动一个后台进程
    /// @param exePath exe文件路径
    /// @param args 启动参数
    /// @param workDirectory
    /// @return 返回进程信息
    static ProcessInformation StartBackgroundProcess(
        const std::string& exePath,
        const std::string& args = "",
        const std::string& workDirectory = "");

    /// @brief 复制当前进程到一个后台进程
    /// @param args 启动参数
    /// @return 返回进程信息
    static ProcessInformation ForkBackgroundProcess(const std::string& args = "");

    /// @brief 获取进程 exe 路径
    /// @param pid 进程id
    /// @return 返回 exe 路径
    static std::filesystem::path GetProcessExePath(DWORD pid);

    /// @brief 等待指定进程退出，并返回其退出码
    /// @param pid 目标进程 ID
    /// @return 进程的退出码
    /// @throws std::system_error 如果打开进程失败
    static DWORD WaitProcessExit(DWORD pid, DWORD dwMilliseconds)
    {
        // 1. 使用 RAII 封装进程句柄（自动关闭）
        struct HandleDeleter
        {
            void operator()(HANDLE h) const
            {
                if (h)
                    ::CloseHandle(h);
            }
        };
        using UniqueHandle = std::unique_ptr<void, HandleDeleter>;

        // 2. 打开进程（有限权限，避免不必要的 PROCESS_ALL_ACCESS）
        UniqueHandle hProcess(::OpenProcess(
            SYNCHRONIZE | PROCESS_QUERY_LIMITED_INFORMATION, // 仅需同步和查询权限
            FALSE,
            pid));

        if (!hProcess)
        {
            // 3. 使用系统错误码抛出异常（包含错误描述）
            throw std::system_error(
                ::GetLastError(),
                std::system_category(),
                "Failed to open process");
        }

        // 4. 等待进程退出
        if (::WaitForSingleObject(hProcess.get(), dwMilliseconds) == WAIT_FAILED)
        {
            throw std::system_error(
                ::GetLastError(),
                std::system_category(),
                "WaitForSingleObject failed");
        }

        // 5. 获取退出码
        DWORD exitCode = 0;
        if (!::GetExitCodeProcess(hProcess.get(), &exitCode))
        {
            throw std::system_error(
                ::GetLastError(),
                std::system_category(),
                "GetExitCodeProcess failed");
        }

        return exitCode;
    }

    /// @brief 启动一个进程
    /// @param exePath exe文件路径
    /// @param args 启动参数
    /// @param dwCreationFlags 启动标志
    /// @param workDirectory
    /// @return 返回进程信息
    static ProcessInformation StartProcess(
        const std::string& exePath,
        DWORD dwCreationFlags,
        const std::string& args,
        const std::string& workDirectory)
    {
        PROCESS_INFORMATION pi = { 0 };

        // 1. 参数校验
        if (exePath.empty())
        {
            throw std::invalid_argument("Executable path cannot be empty");
        }

        // 2. 构造命令行字符串（安全拼接）
        std::string commandLine = "\"" + exePath + "\""; // 处理路径含空格
        if (!args.empty())
        {
            commandLine += " " + args;
        }

        // 3. 初始化结构体（RAII 风格）
        STARTUPINFOA si = { sizeof(STARTUPINFOA) };

        // 4. 启动进程
        BOOL success = ::CreateProcessA(
            exePath.empty() ? nullptr : exePath.c_str(),             // 应用程序路径
            commandLine.data(),                                      // 命令行（需可修改）
            nullptr,                                                 // 进程安全属性
            nullptr,                                                 // 线程安全属性
            FALSE,                                                   // 不继承句柄
            dwCreationFlags,                                         // 后台标志
            nullptr,                                                 // 使用父进程环境块
            workDirectory.empty() ? nullptr : workDirectory.c_str(), // 启动目录
            &si,
            &pi);

        // 5. 错误处理
        if (!success)
        {
            throw std::system_error(
                ::GetLastError(),
                std::system_category(),
                "CreateProcessA failed");
        }

        return ProcessInformation(pi);
    }

    /// @brief 启动一个后台进程
    /// @param exePath exe文件路径
    /// @param args 启动参数
    /// @param workDirectory
    /// @return 返回进程信息
    static ProcessInformation StartBackgroundProcess(
        const std::string& exePath,
        const std::string& args,
        const std::string& workDirectory)
    {
        return StartProcess(exePath, CREATE_NO_WINDOW | DETACHED_PROCESS, args, workDirectory);
    }

    /// @brief 复制当前进程到一个后台进程
    /// @param args 启动参数
    /// @return 返回进程信息
    static ProcessInformation ForkBackgroundProcess(const std::string& args)
    {
        // 获取当前进程的 exe
        auto exePath = CppWinApi::Windows::WinProcess::GetProcessExePath(::GetCurrentProcessId());
        auto workDir = exePath.parent_path();
        return StartBackgroundProcess(exePath.string(), args, workDir.string());
    }

    /// @brief 获取进程 exe 路径
    /// @param pid 进程id
    /// @return 返回 exe 路径
    static std::filesystem::path GetProcessExePath(DWORD pid)
    {
        // 使用 unique_ptr + 自定义删除器实现 RAII 自动关闭句柄
        auto CloseHandleDeleter = [](HANDLE h)
            { if (h) CloseHandle(h); };
        std::unique_ptr<void, decltype(CloseHandleDeleter)> hProcess{
            OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, pid),
            CloseHandleDeleter };

        if (!hProcess)
        {
            throw std::system_error(
                GetLastError(),
                std::system_category(),
                "OpenProcess failed");
        }

        // 使用 wchar_t 版本避免路径编码问题
        wchar_t szExePath[MAX_PATH] = { 0 };
        DWORD size = MAX_PATH;
        if (!QueryFullProcessImageNameW(hProcess.get(), 0, szExePath, &size))
        {
            throw std::system_error(
                GetLastError(),
                std::system_category(),
                "QueryFullProcessImageNameW failed");
        }

        return std::filesystem::path(szExePath);
    }

    /// @brief 判断进程是否存在
    /// @param pid 进程 id
    /// @return 进程存在返回 true，不存在返回 false
    bool IsProcessExist(DWORD pid)
    {
        HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pid);
        if (hProcess != NULL)
        {
            CloseHandle(hProcess); // 进程存在，关闭句柄
            return true;
        }
        return false; // 进程不存在或权限不足
    }
}